#include "snakeserver.h"

SnakeServer::SnakeServer(QObject *parent) :
    QObject(parent)
{
    server = new QTcpServer(this);

    if(!server->listen(QHostAddress::Any, 1234))
    {
        qDebug() << "Server not start!\n";
        return;
    }
    qDebug() << "Server started!\n";

    connect(server, SIGNAL(newConnection()), this, SLOT(slotNewConnection()));

    game = new SnakeGame(this);

    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
    timer->start(100);
    freeplace.push_back(true);

    time = 0;
}

void SnakeServer::slotNewConnection()
{
    QTcpSocket *client = server->nextPendingConnection();

    QVector<bool >::iterator it = freeplace.begin();
    quint32 ID = 1;
    while(it != freeplace.end())
    {
        if(*it)
        {
            (*it)= false;
            break;
        }
        if(it == (freeplace.end() - 1))
        {
            freeplace.push_back(false);
            ID++;
            break;
        }
        ID++;
        it++;
    }
    qDebug() << "New connection! ID = " << QString::number(ID);

    clients.insert(ID, client);

    game->addSnake(ID);

    QString map("[map: ");
    map.push_back(game->getField());
    map.push_back(" ]");
    sendToClient(ID,map);

    QString snake("[your snake: ID = ");
    snake.push_back(QString::number(ID));
    snake.push_back(" points = ");
    snake.push_back(QString::number(game->getPointsOfSnake(ID)));
    snake.push_back(' ');
    snake.push_back(game->getSnakeBody(ID));
    snake.push_back(" ]");
    sendToClient(ID,snake);

    QString newSnake("[new snake: ID = ");
    newSnake.push_back(QString::number(ID));
    newSnake.push_back(" points = ");
    newSnake.push_back(QString::number(game->getPointsOfSnake(ID)));
    newSnake.push_back(' ');
    newSnake.push_back(game->getSnakeBody(ID));
    newSnake.push_back(" ]");
    QString otherSnakes("[other snakes:");
    foreach(quint32 curID, clients.keys())
    {
        if(curID != ID)
        {
            sendToClient(curID, newSnake);
            otherSnakes.push_back(" ID = ");
            otherSnakes.push_back(QString::number(curID));
            otherSnakes.push_back(" points = ");
            otherSnakes.push_back(QString::number(game->getPointsOfSnake(curID)));
            otherSnakes.push_back(' ');
            otherSnakes.push_back(game->getSnakeBody(curID));
        }
    }
    otherSnakes.push_back(" ]");
    sendToClient(ID,otherSnakes);

    QString existBonuses("[Bonuses: ");
    existBonuses.push_back(game->getBonuses());
    existBonuses.push_back(" ]");
    sendToClient(ID,existBonuses);


    QString newBonus("[new bonus: ID = ");
    newBonus.push_back(QString::number(ID));
    newBonus.push_back(' ');
    newBonus.push_back(game->getBonus(ID));
    newBonus.push_back(" ]");
    foreach(quint32 curID, clients.keys())
        sendToClient(curID, newBonus);


    connect(client, SIGNAL(readyRead()),this,SLOT(slotReadyRead()));
    connect(client, SIGNAL(disconnected()), this, SLOT(slotDisconected()));

}

void SnakeServer::slotReadyRead()
{
    QTcpSocket *client = (QTcpSocket *)sender();
    QDataStream in(client);
    in.setVersion(QDataStream::Qt_4_8);
    QString str;
    quint32 blockSize = 0;
    for(;;)
    {
        if(!blockSize)
            if(client->bytesAvailable()<sizeof(quint32))
                break;
            else
                in >> blockSize;
        if(client->bytesAvailable()<blockSize)
            break;
        in >> str;
        blockSize = 0;
    }
    quint32 id = clients.key(client);
    QString numToStr = QString::number(id);
    qint32 poz = curMsg.indexOf(numToStr,0);
    if(poz == -1)
    {
        curMsg.push_back(QString::number(id));
        curMsg.push_back(str[0].toAscii());
    }
    else
    {
        curMsg[poz + numToStr.size()] = str[0].toAscii();
    }

    qDebug() << QString::number(id) << ": " << str << endl;
}

void SnakeServer::slotTimeout()
{
    time ++;
    qDebug() << time << clients.size();
    QString gameAnswer("[update: ");
    gameAnswer.push_back(game->updateSituation(curMsg));
    gameAnswer.push_back("]");
    foreach(quint32 ID, clients.keys())
        sendToClient(ID, gameAnswer);
    curMsg = "";

}

void SnakeServer::slotDisconected()
{
    QTcpSocket *client = (QTcpSocket *) sender();
    quint32 id = clients.key(client);
    clients.erase(clients.find(id));
    game->deleteSnake(id);
    client->deleteLater();
    QString disconnectMsg("[Disconnected: ");
    disconnectMsg.push_back(QString::number(id));
    disconnectMsg.push_back(" ]");
    foreach(quint32 curID, clients.keys())
        sendToClient(curID,disconnectMsg);
    freeplace[id-1] = true;
    qDebug() << "Disconected "<< QString::number(id)<< endl;
}

void SnakeServer::sendToClient(quint32 ID, QString msg)
{
    QByteArray arrBlock;
    QDataStream out(&arrBlock, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_8);
    out << (quint32)0;
    out << msg;
    out.device()->seek(0);
    out << quint32(arrBlock.size() - sizeof(quint32));

    clients.value(ID)->write(arrBlock);
}
